﻿using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Reflection;
using System.Windows.Markup;
using System.Windows.Reflection;

namespace System.Windows.Controls
{
    /// <summary>
    /// Implements a custom <see cref="System.Windows.Controls.ItemControl"/> for use in the <see cref="CloudView"/> view control.
    /// </summary>
    public class CloudViewItem : System.Windows.Controls.ItemControl
    {
        /// <summary>
        /// Instantiates a <see cref="CloudViewItem"/> instance.
        /// </summary>
        public CloudViewItem()
        {
            this.DefaultStyleKey = typeof(CloudViewItem);
            this.HorizontalContentAlignment = HorizontalAlignment.Center;
            this.MinWidth = this.MinHeight = 96;

            translate = new TranslateTransform();
            this.RenderTransform = translate;

            //Center Reveals
            revealStory = Animation.CreateStoryboard(TimeSpan.FromSeconds(0.25));
            moveX = Animation.CreateAnimation(revealStory, translate, "X", 0, 0);
            revealStory.Children.Add(moveX);
            moveY = Animation.CreateAnimation(revealStory, translate, "Y", 0, 0);
            revealStory.Children.Add(moveY);
            fadeAnim = Animation.CreateAnimation(revealStory, this, "Opacity", 0, 0);
            revealStory.Children.Add(fadeAnim);
            this.Resources.Add(revealStory);
        }

        private CloudPanel          _ParentPanel;
        private Storyboard          revealStory;
        private DoubleAnimation     moveX;
        private DoubleAnimation     moveY;
        private DoubleAnimation     fadeAnim;
        private TranslateTransform  translate;

        internal CloudPanel ParentPanel
        {
            get { return _ParentPanel; }
            set { _ParentPanel = value; }
        }

        internal void SetAnimationOrigin(double x, double y, double opacity)
        {
            moveX.From = x;
            moveX.To = 0;
            moveY.From = y;
            moveY.To = 0;
            fadeAnim.From = opacity;
            fadeAnim.To = 1;
        }

        internal void StartAnimation()
        {
            revealStory.Begin();
        }

        /// <summary>
        /// (Override) Handles changes to the <see cref="ItemControl.IsSelected"/> property.
        /// </summary>
        /// <param name="selected">The current value of <see cref="ItemControl.IsSelected"/></param>
        protected override void OnIsSelectedChanged(bool selected)
        {
            if (selected)
                BringToFront();
            else
                SendToBack();
        }

        /// <summary>
        /// Brings the <see cref="CloudViewItem"/> to the front of the z-order.
        /// </summary>
        public override void BringToFront()
        {
            if (this.ParentPanel != null)
            {
                _ZIndexCached = this.ZIndex;
                this.ZIndex = ParentPanel.Children.Count - 1;
            }
        }

        /// <summary>
        /// Sends the <see cref="CloudViewItem"/> to the back of the z-order.
        /// </summary>
        public override void SendToBack()
        {
            if (this.ParentPanel != null)
            {
                _ZIndexCached = this.ZIndex;
                this.ZIndex = 0;
            }
        }

        /// <summary>
        /// (Override) Handlers the Mouse Enter event for the <see cref="CloudViewItem"/> instance.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Input.MouseEventArgs"/> event argument</param>
        protected override void OnMouseEnter(MouseEventArgs e)
        {
            if (!this.IsSelected) this.BringToFront();
            base.OnMouseEnter(e);
        }

        /// <summary>
        /// (Override) Handlers the Mouse Leave event for the <see cref="CloudViewItem"/> instance.
        /// </summary>
        /// <param name="e">The <see cref="System.Windows.Input.MouseEventArgs"/> event argument</param>
        protected override void OnMouseLeave(MouseEventArgs e)
        {
            if (!this.IsSelected) this.SendToBack();
            base.OnMouseLeave(e);
        }
    }

    /// <summary>
    /// A collection of <see cref="CloudViewItem"/> instances.
    /// </summary>
    public class CloudViewItems : System.Collections.Generic.List<CloudViewItem>
    {

    }

    /// <summary>
    /// Implements a class which handles sorting for a single axis of a <see cref="CloudView"/> instance.
    /// </summary>
    public class CloudSorter : ArrangeSorter, IComparer<CloudViewItem>
    {
        /// <summary>
        /// Instantiates a <see cref="CloudSorter"/> instance.
        /// </summary>
        /// <param name="sortField">The field or property name to sort by</param>
        /// <param name="direction">The direction of the sort</param>
        public CloudSorter(string sortField, SortDirections direction) : base(sortField, direction)
        {
        }

        #region IComparer<CloudViewItem> Members

        /// <summary>
        /// Compares two instances of a <see cref="CloudViewItem"/>.
        /// </summary>
        /// <param name="x">The first <see cref="CloudViewItem"/></param>
        /// <param name="y">The second <see cref="CloudViewItem"/></param>
        /// <returns></returns>
        public int Compare(CloudViewItem x, CloudViewItem y)
        {
            if (String.IsNullOrEmpty(this.SortField)) throw new InvalidOperationException(SystemResources.ERR_CLOUDSORTER_NO_FIELD);

            object dataX = x.DataContext;
            object dataY = y.DataContext;

            if (dataX != null && dataY != null)
            {
                object valX = GetSortValue(this.SortField, dataX);
                object valY = GetSortValue(this.SortField, dataY);

                if (valX != null && valX is IComparable && valY != null && valY is IComparable)
                {
                    if (this.SortDirection == SortDirections.Ascending)
                        return ((IComparable)valX).CompareTo(valY);
                    else
                        return ((IComparable)valY).CompareTo(valX);
                }
            }

            return 0;
        }

        #endregion
    }
}
